package com.tencent.elife.asyn;

import java.io.IOException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.HttpHostConnectException;
import org.json.JSONException;

import android.content.Context;
import android.os.Handler;

/**
 * @Description 异步任务管理的基类，拥有一个带消息循环的后台工作线程
 * @author zijianlu
 */
public abstract class BaseManager {
    private Handler mWorkerHandler = null;
    private Handler mUIHandler = null;
    private WorkerThread mWorkerThread = null;
    private List<Runnable> mRequestTask = new ArrayList<Runnable>();

    /** 初始化，全局调用一次 */
    public void init(Context appCtx) {
        if (mWorkerHandler == null) {
            mWorkerThread = new WorkerThread();
            mWorkerHandler = mWorkerThread.getHandler();
            mUIHandler = new Handler(appCtx.getMainLooper());
        }
    }

    /** 退出工作线程的消息循环 ，全局调用一次 */
    public synchronized void release() {
        if (mWorkerThread != null) {
            mWorkerThread.quit();
            mWorkerThread = null;
        }

        mWorkerHandler = null;
        mRequestTask = null;
    }

    /** 清空任务队列, 还未执行的任务将不会再执行，正在执行的任务执行到结束 */
    public synchronized void reset() {
        reset(false);
    }

    /**
     * 清空任务队列, 还未执行的任务将不会再执行，正在执行的任务执行到结束, cancelTask是否还执行回调
     */
    public synchronized void reset(boolean cancelTask) {
        if (mWorkerHandler != null && mRequestTask != null) {
            int size = mRequestTask.size();
            for (int i = 0; i < size; i++) {
                if (cancelTask) {
                    CancelableTask task = (CancelableTask) mRequestTask.get(i);
                    task.cancel();
                }
                mWorkerHandler.removeCallbacks(mRequestTask.get(i));
            }
            mRequestTask.clear();
        }
    }

    public void onFinish(Command<?> cmd) {
        DataResponse<?> response = cmd.getResponse();
        if (response != null && mUIHandler != null) {
            mUIHandler.post(response);
        }
    }

    public void onError(final Exception exception, final Command<?> cmd) {
        final DataResponse<?> response = cmd.getResponse();
        if (response != null && mUIHandler != null) {
            try {
                throw exception;
            } catch (JSONException e) {
                response.errCode = ErrorCode.CODE_JSON_PARSER_ERROR;
            } catch (IOException e) {
                if (e instanceof ConnectTimeoutException
                    || e instanceof SocketTimeoutException) {
                    response.errCode = ErrorCode.CODE_REQUEST_TIME_OUT;
                } else if (e instanceof UnknownHostException
                    || e instanceof HttpHostConnectException
                    || e instanceof SocketException) {
                    response.errCode = ErrorCode.CODE_UNKNONW_HOST;

                } else {
                    response.errCode = ErrorCode.CODE_GENNERAL_IO_ERROR;
                }
            } catch (IllegalArgumentException e) {
                response.errCode = ErrorCode.CODE_WRONG_DATA_FORMAT;
            } catch (Exception e) {
                response.errCode = ErrorCode.CODE_UNCAUGHT_ERROR;
            }

            mUIHandler.post(new Runnable() {
                @Override
                public void run() {
                    response.onError(response.errCode, exception.toString(),
                        cmd, BaseManager.this);
                }
            });
        }
    }

    /** 重试 */
    public boolean retry(Runnable cmd) {
        return postCommand(cmd);
    }

    /** 添加异步任务 */
    protected <T> void addTask(DataRequest<T> request, DataResponse<T> response) {
        postCommand(new Command<T>(request, response, this));
    }

    private synchronized boolean postCommand(Runnable r) {
        if (mWorkerHandler != null && mRequestTask != null) {
            mRequestTask.add(r);
            return mWorkerHandler.post(r);
        }
        return false;
    }

    /** 错误码 */
    public static class ErrorCode {
        public final static int CODE_SUCCESS = 1000;
        public final static int CODE_UNKNONW_HOST = 1001;
        public final static int CODE_WRONG_DATA_FORMAT = 1002;
        public final static int CODE_REQUEST_TIME_OUT = 1003;
        public final static int CODE_CONNECT_ERROR = 1004;
        public final static int CODE_GENNERAL_IO_ERROR = 1005;
        public final static int CODE_NOT_FOUND_ERROR = 1006;
        public final static int CODE_JSON_PARSER_ERROR = 1007;
        public final static int CODE_UNCAUGHT_ERROR = 1008;
        public final static int CODE_404_ERROR = 1009;
    }
}
